package main

import (
	"encoding/json"
	"html/template"
	"log"
	"mime"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/gorilla/sessions"
)

const urlPrefix = "/gpssignin"

func main() {
	// 连接mongodb
	InitDB()

	// http
	mime.AddExtensionType(".apk", "application/vnd.android.package-archive")
	http.HandleFunc(urlPrefix+"/register", handleRegister) // 用户注册。客户端调用
	http.HandleFunc(urlPrefix+"/login", handleLogin)       // 用户登录/打卡。客户端调用
	http.HandleFunc(urlPrefix+"/gps", handleGPS)           // 上传位置信息。客户端调用

	http.HandleFunc(urlPrefix+"/adminlogin", handleAdminLogin) // 后台管理员登录
	http.HandleFunc(urlPrefix+"/queryuser", handleQueryUser)   // 后台查询用户
	http.HandleFunc(urlPrefix+"/displaygps", handleDisplayGPS) // 展示用户GPS

	http.HandleFunc(urlPrefix+"/querygps", handleQueryGPS)                                                           // 查询位置信息。html中调用
	http.Handle(urlPrefix+"/public/", http.StripPrefix(urlPrefix+"/public/", http.FileServer(http.Dir("./public")))) // 静态页面
	http.Handle("/", http.RedirectHandler(urlPrefix+"/queryuser", http.StatusFound))                                 // 后台查询用户

	const serverAddr = ":8091"
	log.Printf("server listen at %v...", serverAddr)
	log.Fatalf("listen and serve: %v", http.ListenAndServe(serverAddr, nil))
}

// curl "http://127.0.0.1:8091/gpssignin/register?phone=13770641012&password=580608"
func handleRegister(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleRegister:")

	_ = r.ParseForm()
	// 如果用户已存在，则注册失败，返回400
	if UserAlreadyExists(r.FormValue("phone")) {
		w.WriteHeader(http.StatusBadRequest)
		log.Printf("ERROR phone[%v] register error", r.FormValue("phone"))
		return
	}

	// 如果用户不存在，则注册成功，且加入到全局users中
	SaveNewUser(&User{
		Phone:    r.FormValue("phone"),
		Password: r.FormValue("password"),
		Name:     r.FormValue("name"),
	})

	w.WriteHeader(http.StatusOK)
	log.Printf("phone[%v] register success", r.FormValue("phone"))
}

// curl "http://127.0.0.1:8091/gpssignin/login?phone=13770641012&password=580608"
func handleLogin(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleLogin:")

	_ = r.ParseForm()

	user := UserLogin(r.FormValue("phone"), r.FormValue("password"))
	if user != nil {
		userJSON, _ := json.Marshal(user)
		w.WriteHeader(http.StatusOK)
		w.Write(userJSON)
		log.Printf("phone[%v] login success", user.Phone)
		return
	}

	w.WriteHeader(http.StatusBadRequest)
	log.Printf("phone[%v] login error", r.FormValue("phone"))
}

// var (
// 	date = "2017-11-10 20:40"
// 	lon  = 118.73251738
// 	lat  = 31.97559901
// )

// curl "http://127.0.0.1:8091/gpssignin/gps?phone=13770641012&password=580608&lon=118.73251738&lat=31.97559901"
func handleGPS(w http.ResponseWriter, r *http.Request) {
	_ = r.ParseForm()

	phone := r.FormValue("phone")
	password := r.FormValue("password")
	log.Printf("handleGPS: phone[%v]", phone)
	//  longitude and latitude
	var err error
	lon, err := strconv.ParseFloat(r.FormValue("lon"), 64)
	if err != nil {
		log.Printf("parse lon error: %v", err)
		return
	}
	lat, err := strconv.ParseFloat(r.FormValue("lat"), 64)
	if err != nil {
		log.Printf("parse lon error: %v", err)
		return
	}

	err = GPSSave(phone, password, lon, lat)
	if err != nil {
		log.Printf("GPSSave() error: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	w.WriteHeader(http.StatusOK)
}

var loc *time.Location

// curl "http://127.0.0.1:8091/gpssignin/querygps?phone=13770641012&start=2017-11-30&stop=2017-12-03"
func handleQueryGPS(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleQueryGPS:")

	_ = r.ParseForm()
	phone := r.FormValue("phone")
	start, err := time.ParseInLocation("2006-01-02 15:04:05", r.FormValue("start"), loc)
	if err != nil {
		log.Printf("handleQueryGPS get formvalue start error: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	log.Printf("start: %v", start)
	stop, err := time.ParseInLocation("2006-01-02 15:04:05", r.FormValue("stop"), loc)
	if err != nil {
		log.Printf("handleQueryGPS get formvalue stop error: %v", err)
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	log.Printf("stop: %v", stop)

	w.Header().Set("Content-Type", "application/json")

	gps, _ := GPSQuery(phone, start, stop)
	for _, g := range gps {
		g.TimeStr = g.Time.Format("2006-01-02 15:04:05")
	}

	content, _ := json.Marshal(gps)
	w.Write(content)
}

// func handleDisplayGPS(w http.ResponseWriter, r *http.Request) {
// 	log.Printf("handleDisplayGPS:")

// 	_ = r.ParseForm()
// 	phone := r.FormValue("phone")
// 	start := r.FormValue("start")
// 	stop := r.FormValue("stop")

// 	if phone == "" || start == "" || stop == "" {
// 		w.WriteHeader(http.StatusBadRequest)
// 		return
// 	}

// 	// TODO render html

// }

var gpsTemplates *template.Template

func init() {
	var err error
	gpsTemplates, err = template.New("adminlogin").ParseFiles("public/adminlogin.html", "public/queryuser.html", "public/displaygps.html")
	if err != nil {
		log.Panicf("parse templates error: %v", err)
	}

	if loc == nil {
		loc, err = time.LoadLocation("Asia/Shanghai")
		if err != nil {
			log.Panicf("time.loadlocation error: %v", err)
		}
	}
}

var store = sessions.NewCookieStore([]byte("something-very-secret"))

func handleAdminLogin(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleAdminLogin()")

	if r.Method == http.MethodGet {
		gpsTemplates.ExecuteTemplate(w, "adminlogin.html", nil)
		return
	}

	// post form
	_ = r.ParseForm()
	phone := r.FormValue("phone")
	password := r.FormValue("password")
	user := checkUser(phone, password)
	if user == nil || !user.IsAdmin {
		// 如果不是有效用户或者不是管理员
		log.Printf("checkUser error")
		gpsTemplates.ExecuteTemplate(w, "adminlogin.html", nil)
		return
	}

	// 写入cookie
	session, _ := store.Get(r, "session-name")
	session.Values["phone"] = phone
	session.Values["password"] = password
	session.Values["isadmin"] = user.IsAdmin
	session.Save(r, w)

	// 重定向到queryuser
	log.Printf("redirect to /queryuser")
	http.Redirect(w, r, urlPrefix+"/queryuser", http.StatusFound)
	return
}

func handleQueryUser(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleQueryUser()")
	// 先取cookie。如果无cookie，则跳转回adminlogin
	session, _ := store.Get(r, "session-name")

	if session.Values["isadmin"] == nil || !session.Values["isadmin"].(bool) {
		log.Printf("not admin")
		http.Redirect(w, r, urlPrefix+"/adminlogin", http.StatusFound)
		return
	}

	if r.Method == http.MethodGet {
		gpsTemplates.ExecuteTemplate(w, "queryuser.html", nil)
		return
	}

	// post form
	_ = r.ParseForm()
	phone := r.FormValue("phone")
	start := r.FormValue("start")
	stop := r.FormValue("stop")
	log.Printf("redirect to displaygps")

	http.Redirect(w, r, urlPrefix+"/displaygps?phone="+url.QueryEscape(phone)+"&start="+url.QueryEscape(start)+"&stop="+url.QueryEscape(stop), http.StatusFound)
}

func handleDisplayGPS(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleDisplayGPS()")
	// 鉴权
	session, _ := store.Get(r, "session-name")

	if session.Values["isadmin"] == nil || !session.Values["isadmin"].(bool) {
		log.Printf("not admin")
		http.Redirect(w, r, urlPrefix+"/adminlogin", http.StatusFound)
		return
	}

	_ = r.ParseForm()
	phone := r.FormValue("phone")
	start := r.FormValue("start")
	stop := r.FormValue("stop")
	data := map[string]interface{}{
		"phone": phone,
		"start": start,
		"stop":  stop,
	}
	gpsTemplates.ExecuteTemplate(w, "displaygps.html", data)
}

func handleDownloadAPK(w http.ResponseWriter, r *http.Request) {
	log.Printf("handleDownloadAPK()")

	http.ServeFile(w, r, "public/kaoqin_v1.apk")
}
